#ifndef __THREAD_POOL_H__
#define __THREAD_POOL_H__
#define _SERVER_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#include <error.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <signal.h>
#include <dirent.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/epoll.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <sys/uio.h>
#include <sys/sendfile.h>
#include <mysql/mysql.h>
#include <openssl/evp.h>
#define SIZE(a) (sizeof(a)/sizeof(a[0]))

#define ARGS_CHECK(argc, num)   {\
    if(argc != num){\
        fprintf(stderr, "ARGS ERROR!\n");\
        return -1;\
    }}

#define ERROR_CHECK(ret, num, msg) {\
    if(ret == num) {\
        perror(msg);\
        return -1;\
    }}

#define THREAD_ERROR_CHECK(ret, func) {\
    if(ret != 0) {\
        fprintf(stderr, "%s:%s\n", func, strerror(ret));\
    }}

// 用户注册表
typedef struct User{
    int id;
    char userName[64];
    char salt[64];
    char cryptpasswd[65];
    char pwd[64];
}User;

// 服务器文件表
typedef struct FileInfo{
    char md5[64];
    char fileName[64];
}FileInfo;

// 虚拟文件表
typedef struct FileEntry{
    int id;
    int parentId;
    char fileName[64];
    int ownerId;
    char md5[64];
    int fileSize;
    int fileType;
}FileEntry;

typedef enum {
    CMD_TYPE_PWD=1,
    CMD_TYPE_LS,
    CMD_TYPE_CD,
    CMD_TYPE_MKDIR,
    CMD_TYPE_RMDIR,
    CMD_TYPE_PUTS,
    CMD_TYPE_GETS,
    CMD_TYPE_REMOVE,
    CMD_TYPE_NOTCMD,  //不是命令

    CMD_TYPE_LOGIN_USRNAME = 100,
    CMD_TYPE_REGISTER_USERNAME,
    CMD_TYPE_LOGIN_ENCRYTPTEDCODE,
    CMD_TYPE_REGISTER_ENCRYTPTEDCODE,
    MSG_TYPE_LOGIN_SALT,
    MSG_TYPE_REGISTER_SALT,
    MSG_TYPE_LOGINOK,
    MSG_TYPE_LOGINERROR,
    MSG_TYPE_REGISTEROK,
    MSG_TYPE_REGISTERERROR,
}CmdType;


typedef struct 
{
    int len;//记录内容长度
    CmdType type;
    User user;  //对应用户信息
    char buff[1000];//记录内容本身
}train_t;

typedef struct task_s{
    int peerfd;//与client进行通信的套接字
    int epfd;//epoll的实例
    CmdType type;
    char data[1000];
    User* user;
    struct task_s * pNext;
}task_t;

typedef struct task_queue_s
{
    task_t * pFront;
    task_t * pRear;
    int queSize;//记录当前任务的数量
    pthread_mutex_t mutex; 
    pthread_cond_t cond;
    int flag;//0 表示要退出，1 表示不退出

}task_queue_t;

typedef struct threadpool_s {
    pthread_t * pthreads;
    int pthreadNum;
    task_queue_t que;//...任务队列
}threadpool_t;


int queueInit(task_queue_t *que); // 队列初始化
int queueDestroy(task_queue_t *que); // 队列的销毁
int queueIsEmpty(task_queue_t *que); // 判断队列是否为空
int taskSize(task_queue_t * que);// 队列的大小
int taskEnque(task_queue_t *que, task_t *ptask); // 入队
int taskDeque(task_queue_t *que, task_t **ptask); // 出队
int broadcastALL(task_queue_t *que);


int threadpoolInit(threadpool_t *pthreadpool, int num); // 线程池初始化
int threadpoolDestroy(threadpool_t *pthreadpool); // 销毁线程池
int threadpoolStart(threadpool_t *pthreadpool); // 启动线程池
int threadpoolStop(threadpool_t *pthreadpool); // 暂停线程池


int tcpInit(const char * ip, const char * port);  // tcp连接初始化
int addEpollReadfd(int epfd, int fd); // 加入epoll监听
int delEpollReadfd(int epfd, int fd); // 去除epoll监听
/* int transferFile(int sockfd); */  
int sendn(int sockfd, const void * buff, int len); // 确定发送len字节的数据
int recvn(int sockfd, void * buff, int len); // 确定接收len字节的数据

//处理客户端发过来的消息
int handleMessage(int sockfd, int epfd, task_queue_t * que);
int doTask(task_t * task);
//执行任务的总的函数
int doTask(task_t * task);

//每一个具体命令的执行
int cdCommand(task_t * task);
int lsCommand(task_t * task);
int pwdCommand(task_t * task);
int mkdirCommand(task_t * task);
int rmdirCommand(task_t * task);
int notCommand(task_t * task);
int putsCommand(task_t * task);
int getsCommand(task_t * task);
int removeCommand(task_t * task);

// 用户注册
int register_server(task_t * task);
// 用户注册：先收用户名
int userRegister1(task_t* task);
// 用户注册：接收密码
int userRegister2(task_t* task);
// 产生盐值
int generateSalt(char* salt,size_t length);

// 用户登录的操作
// 用户登录1: 接收用户名，对比用户表该用户是否存在。存在发盐值，不存在不发。
int userLoginCheck1(task_t * task);
// 用户登录2:验证密码
int userLoginCheck2(task_t * task);

// 数据库，返回0成功，返回-1失败，实体返回NULL为失败
// 用户表
int addUser(User* user); // 添加用户
User* selectUser(int userId); // 根据userid查询用户信息
int updateUser(User* user); // 更新用户信息
User* selectUserByUserName(const char* userName); // 根据用户名查询用户信息

//文件表
int addFileInfo(FileInfo* fileInfo); // 添加文件表
FileInfo* selectFileInfo(char* md5, int md5Len); // 查询文件表
int updateFileInfo(FileInfo* fileInfo, const char* oldMd5); // 更新文件表

//虚拟文件表
int addFileEntry(FileEntry* fileEntry); // 插入虚拟文件表
FileEntry* selectFileEntry(int id); // 查询虚拟文件表
int updateFileEntry(FileEntry* fileEntry); // 更新虚拟文件表
int deleteFileEntry(int id); // 删除虚拟文件表
FileEntry* selectFileEntryByFileName(const char* fileName); // 根据FileName查询虚拟文件信息
FileEntry* selectFileEntryByOwnerId(int ownerId, int* entryCount); // 根据ownerId查询虚拟文件信息
FileEntry* selectFileEntryByparentId(int parentId, int* entryCount); // 根据parentId查询虚拟文件信息
FileEntry* selectFileEntryByFileNameAndOwnerId(const char* fileName, int ownerId, int* entryCount); // 根据FileNameAndOwnerId查询虚拟文件信息
FileEntry* selectFileEntryByOwnerIdAndFileType(int ownerId, int fileType, int* entryCount); // 根据OwnerIdAndFileType查询虚拟文件信息
FileEntry* selectFileEntryByFileNameParentIdOwnerId(const char* fileName, int parentId, int ownerId); // 根据FileNameParentIdOwnerId查询虚拟文件信息

// 根据dir查找并返回文件或目录条目
FileEntry* getEntriesInDir(int dirId);
// 根据路径查找并返回文件或目录条目
FileEntry* getEntryByPath(const char *path);

// 获取pwd的最后一个目录项和倒数第二个目录项
int getCurrentDirectory(const char*, char **currentDirectory);
int getParentDirectory(const char* pwd, char **parentDirectory);

// 去掉获取的data后面的空格
int removeTrailingSpace(char* str);

//对指定文件生成相应的MD5值
int generateMD5(const char *filename, char *md5String);
int getUserPWD(const char* username, char **userPwd); // 根据用户名获取用户密码的函数
MYSQL* create_db_connection();


#endif 
